home *** CD-ROM | disk | FTP | other *** search
- /* Balloonify.c - this is the meat of this program.
- pseudo code:
- • open input file
- • create output file.
- • open output file
- • BalloonifyMenus
- BalloonifyDialogs
- • close output file
- • close input file
-
- November 11, 1996: I, David Phillip Oster, place this source code in the public
- domain. This means you can do anyhing you want with it.
- It would be considerate if you kept me posted on any bugs, bug fixes, or
- improvements.
- oster@netcom.com
- */
- #include <stdlib.h>
- #include <Balloons.h>
- #include "Balloonify.h"
- #include "BalloonyRes.h"
-
- /* DitlItemRec - this actually varies in size, so don't use sizeof of it.
- an item in a DITl resource.
- used for functions that probe a DITl resource
- */
- typedef struct DitlItemRec {
- LongInt handOrPtr;
- Rect r;
- char type;
- char len;
- Integer resID; /* present only in control items. */
- }DitlItemRec, *DitlItemPtr;
-
- /* A CNTL resource - used for functions that probe a CNTL resource
- */
- typedef struct CtlItemRec {
- Rect r;
- Integer val;
- Integer vis;
- Integer max;
- Integer min;
- Integer procId;
- LongInt refCon;
- Str255 title;
- }CtlItemRec, *CtlItemPtr, **CtlItemHandle;
-
- static StringPtr wild1S;
- static StringPtr wild2S;
- static StringPtr wild3S;
- static StringPtr minusS;
- static StringPtr oneS;
- static StringPtr commaReturnS;
- static StringPtr commaS;
- static StringPtr hS;
- static StringPtr menuS;
- static StringPtr hmnuS;
- static StringPtr cntlS;
- static StringPtr buttonS;
- static StringPtr checkBoxS;
- static StringPtr radioButtonS;
- static StringPtr textS;
- static StringPtr editS;
- static StringPtr iconS;
- static StringPtr pictS;
- static StringPtr userS;
- static StringPtr unknownS;
- static StringPtr ditlS;
- static StringPtr hdlgS;
-
- static StringPtr *initStrs[] = {
- &wild1S,
- &wild2S,
- &wild3S,
- &minusS,
- &oneS,
- &commaReturnS,
- &commaS,
- &hS,
- &menuS,
- &hmnuS,
- &cntlS,
- &buttonS,
- &checkBoxS,
- &radioButtonS,
- &textS,
- &editS,
- &iconS,
- &pictS,
- &userS,
- &unknownS,
- &ditlS,
- &hdlgS,
- NIL
- };
-
- /* InitBalloonify - initialize the string pointers
- */
- void InitBalloonify(void){
- StringPtr **spp;
- StringPtr *sp;
- StringPtr p;
- Handle h;
-
- h = GetResource('STR#', kSmallStrs);
- DetachResource(h);
- HLock(h);
- HNoPurge(h);
- p = (StringPtr) (sizeof(Integer) + *h);
- for(spp = initStrs; NIL != *spp ; spp++){
- sp = *spp;
- *sp = p;
- p += Length(p) + 1;
- }
- }
-
- /* *** sort functions
- */
-
- typedef struct SortResRec{
- LongInt id;
- Handle h;
- }SortResRec, *SortResPtr, **SortResHandle;
-
- /* NewSortArray - sort in increasing id order.
- */
- static SortResHandle NewSortArray(Integer size){
- return (SortResHandle) NewHandleClear(size * (LongInt) sizeof(SortResRec));
- }
-
- /* CompareResRec - comparison function for qsort.
- Treat negative numbers as greater than any positive number
- */
- static int CompareResRec(const void * a, const void *b){
- return (unsigned) ((SortResPtr) a)->id - (unsigned) ((SortResPtr) b)->id;
- }
-
- /* NewSortedRes - gather all the resources of a particular type from the
- current resource file, and return them (unloaded) in an array.
- Note: resource files can only hold ~2000 items, so shorts==Integers are safe here.
- */
- static OSErr NewSortedRes(OSType type, SortResHandle *srhp){
- OSErr errCode;
- Integer i, max, id;
- SortResHandle srh;
- Handle h;
- Str255 name;
-
- errCode = noErr;
- max = Count1Resources(type);
- if(NIL == (srh = NewSortArray(max))){
- return memFullErr;
- }
-
- /* fill in the array
- */
- SetResLoad(FALSE);
- for(i = 1 ; i <= max && noErr == errCode ; i++){
- if(NIL != (h = Get1IndResource(type, i))){
- HPurge(h);
- GetResInfo(h, &id, &type, name);
- (*srh)[i-1].h = h;
- (*srh)[i-1].id = id;
- }
- }
- SetResLoad(TRUE);
- if(noErr != errCode){
- if(NIL != srh){
- DisposeHandle((Handle) srh);
- srh = NIL;
- }
- return errCode;
- }
-
- /* shrink to the size actually gathered.
- */
- if(max != i-1){
- max = i-1;
- SetHandleSize((Handle)srh, sizeof(SortResRec)*max);
- }
-
- /* sort the array
- */
- if(max > 1){
- HLock((Handle) srh);
- qsort(*srh, max, sizeof(SortResRec), CompareResRec);
- HUnlock((Handle) srh);
- }
- *srhp = srh;
- return errCode;
- }
-
- /* *** i/o functions.
- */
-
-
- /* FSWriteStr - write a pascal string to the output
- */
- static OSErr FSWriteStr(Integer outRef, const StringPtr s){
- LongInt len;
-
- len = Length(s);
- return FSWrite(outRef, &len, &s[1]);
- }
-
- /* WriteStrSharp - write an entire STR# to the standard output doing pattern replacement as you go.
- */
- static OSErr WriteStrSharp(Integer strsNum, const StringPtr s1, const StringPtr s2, const StringPtr s3, Integer outRef){
- OSErr errCode;
- Integer i, max;
- Handle h;
- Str255 s;
-
- errCode = noErr;
- if(NIL != (h = GetResource('STR#', strsNum))){
- max = ** (Integer **) h;
- for(i = 1 ; i <= max && noErr == errCode; i++){
- GetIndString(s, strsNum, i);
- if(EqualString(s, wild1S, FALSE, FALSE)){
- errCode = FSWriteStr(outRef, s1);
- }else if(EqualString(s, wild2S, FALSE, FALSE)){
- errCode = FSWriteStr(outRef, s2);
- }else if(EqualString(s, wild3S, FALSE, FALSE)){
- errCode = FSWriteStr(outRef, s3);
- }else{
- errCode = FSWriteStr(outRef, s);
- }
- }
- }else{
- return resNotFound;
- }
- return errCode;
- }
-
- /* BalloonifyHeader - dump out the file header.
- */
- static OSErr BalloonifyHeader(StringPtr name, Integer outRef){
- return WriteStrSharp(kHeaderStrs, name, emptyS, emptyS, outRef);
- }
-
- static Integer CountMTItems(const Handle h){
- return CountMItems((MenuHandle) h);
- }
-
- /* GetTItem - retrieve an item from a menuhandle 0 is the title.
- */
- static void GetTItem(const Handle h, Integer i, StringPtr s){
- if(0 == i){
- StrMove( (**(MenuHandle) h).menuData, s);
- }else{
- GetItem((MenuHandle) h, i, s);
- }
- }
-
- /* IsSkipItem - TRUE if we should skip this item.
- */
- static Boolean IsSkipItem(const StringPtr s){
- return Length(s) == 0 ||
- EqualString(minusS, s, FALSE, FALSE) ||
- EqualString("\p\0", s, FALSE, FALSE);
- }
-
-
- /* Stringify -
- */
- static void Stringify(const StringPtr itemS, StringPtr s){
- Integer i;
-
- s[0] = 0;
- for(i = 1 ; i <= Length(itemS); i++){
- switch(itemS[i]){
- case '\0':
- case '\1':
- case '\2':
- case '\3':
- case '\4':
- case '\5':
- case '\6':
- case '\7':
- AppendChar(s, '\\');
- AppendChar(s, itemS[i] + '0');
- break;
- case '\b':
- AppendChar(s, '\\');
- AppendChar(s, 'b');
- break;
- case '\t':
- AppendChar(s, '\\');
- AppendChar(s, 't');
- break;
- case '\n':
- case '\r':
- AppendChar(s, '\\');
- AppendChar(s, 'n');
- break;
- case '"':
- case '\\':
- AppendChar(s, '\\');
- AppendChar(s, itemS[i]);
- break;
- default:
- AppendChar(s, itemS[i]);
- break;
- }
-
- }
- }
-
-
- /* WriteStrItem - write an item to a STR#. mostly just a numericly labeled comma separated string
- */
- static OSErr WriteStrItem(const StringPtr itemS, const StringPtr nameS, const StringPtr helpStrsS, const StringPtr nS, Integer outRef){
- OSErr errCode;
- Str255 s;
-
- errCode = noErr;
- if(IsSkipItem(itemS)){
- return errCode;
- }
- if(NOT EqualString(oneS, nS, FALSE, FALSE)){ /* not first item, put a comma */
- errCode = FSWriteStr(outRef, commaReturnS);
- }
- if(noErr == errCode){ errCode = WriteStrSharp(kRepeatStrs, nameS, helpStrsS, nS, outRef); }
- Stringify(itemS, s);
- AppendChar(s, '"');
- if(noErr == errCode){ errCode = FSWriteStr(outRef, s); }
- return errCode;
- }
-
-
- /* WriteHmnuMenuItem - write an item to an hmnu resource
- */
- static OSErr WriteHmnuMenuItem(const StringPtr itemS, const StringPtr menuS, const StringPtr helpStrsS, const StringPtr nS, Integer outRef){
- OSErr errCode;
- Str255 s;
-
- if(NOT EqualString(oneS, nS, FALSE, FALSE)){ /* not first item, put a comma */
- if(noErr != (errCode = FSWriteStr(outRef, commaS))){
- return errCode;
- }
- }
- if(IsSkipItem(itemS)){
- GetIndString(s, kMainStrs, kSkipItemS);
- return FSWriteStr(outRef, s);
- }else{
- return WriteStrSharp(kHMNUStringResStrs, menuS, helpStrsS, nS, outRef);
- }
- }
-
- /* StripNonAlphaNum - strip non alphanumeric characters from the string.
- */
- static void StripNonAlphaNum(StringPtr menuS){
- Str255 s;
- Integer i;
-
- s[0] = 0;
- for(i = 1 ; i <= Length(menuS); i++){
- if(('0' <= menuS[i] && menuS[i] <= '9') ||
- ('a' <= menuS[i] && menuS[i] <= 'z') ||
- ('A' <= menuS[i] && menuS[i] <= 'Z') ||
- '_' == menuS[i]){
-
- AppendChar(s, menuS[i]);
- }
- }
- StrMove(s, menuS);
- }
-
-
- /* GetMenuName - get a plausible name for this menu.
- */
- static void GetMenuName(const Handle h, StringPtr menuS){
- Integer id;
- OSType type;
- Str255 nS;
-
- GetResInfo(h, &id, &type, menuS);
- if(0 == Length(menuS)){
- GetTItem(h, 0, menuS);
- }
- StripNonAlphaNum(menuS);
- if(0 == Length(menuS)){
- NumToString(id, nS);
- if('-' == nS[1]){
- nS[1] = 'm';
- }
- StrMove(hS, menuS);
- Concat(menuS, nS);
- }
- }
-
-
- /* BalloonifyMenu1 - put out the menu
- 1.) collect the replacement strings.
- 2.) dump out the initial header
- 3.) loop through the items
- 4.) dump out the midedial header
- 5.) loop through the items
- 6.) dump out the closer.
- */
- static OSErr BalloonifyMenu1(Handle h, Integer outRef){
- OSErr errCode;
- Str255 nameS;
- Str255 helpStrsS;
- Str255 itemS;
- Str255 idS;
- Str255 nS;
- Integer i, j, max, id;
- OSType type;
-
- errCode = noErr;
- nameS[0] = helpStrsS[0] = itemS[0] = nS[0] = '\0';
-
- /* 1.) collect the replacement strings.
- */
- GetMenuName(h, nameS);
- StrMove(nameS, helpStrsS);
- errCode = BumpProgress(nameS);
- Concat(nameS, menuS);
- Concat(helpStrsS, hmnuS);
-
- /* 2.) dump out the initial header
- */
- GetResInfo(h, &id, &type, idS);
- NumToString(id, idS);
- if(noErr == errCode){ errCode = WriteStrSharp(kHMNUNormal1Strs, nameS, helpStrsS, idS, outRef); }
- /* 3.) loop through the items
- */
- max = CountMTItems(h);
- for(i = 0, j = 1 ; i <= max && noErr == errCode; i++){
- NumToString(j, nS);
- GetTItem(h, i, itemS);
- if(NOT (IsSkipItem(itemS))){
- errCode = WriteStrItem(itemS, nameS, helpStrsS, nS, outRef);
- j++;
- }
- }
-
- /* 4.) dump out the medial header
- */
- if(noErr == errCode){ errCode = WriteStrSharp(kHMNUMedialStrs, nameS, helpStrsS, nS, outRef); }
-
- /* 5.) loop through the items
- */
- for(i = 0, j = 1; i <= max && noErr == errCode; i++){
- NumToString(j, nS);
- GetTItem(h, i, itemS);
- errCode = WriteHmnuMenuItem(itemS, nameS, helpStrsS, nS, outRef);
- if(NOT (IsSkipItem(itemS))){
- j++;
- }
- }
-
- /* 6.) dump out the closer.
- */
- if(noErr == errCode){ errCode = WriteStrSharp(kHMNUCloseStrs, nameS, helpStrsS, nS, outRef); }
- return errCode;
- }
-
-
- /* BalloonifyMenus - for each menu, write the menu's STR#. write the menu's 'hmnu'
- sorts the menus.
- */
- static OSErr BalloonifyMenus(Integer inRes, Integer outRef){
- OSErr errCode;
- Integer i, max;
- Integer saveResFile;
- Handle h;
- SortResHandle srh;
-
- errCode = noErr;
- saveResFile = CurResFile();
- UseResFile(inRes);
-
- /* get the sorted resources.
- */
- if(noErr != (errCode = NewSortedRes('MENU', &srh))){
- return errCode;
- }
- max = GetHandleSize((Handle) srh) / sizeof(SortResRec);
-
-
- /* process the sorted menus.
- */
- for(i = 0; i < max && noErr == errCode ; i++){
- h = (*srh)[i].h;
- LoadResource(h);
- if(noErr != (errCode = ResError())){
- break;
- }
- HNoPurge(h);
- HLock(h);
- UseResFile(saveResFile);
- errCode = BalloonifyMenu1(h, outRef);
- UseResFile(inRes);
- ReleaseResource(h);
- }
- UseResFile(saveResFile);
- if(NIL != srh){
- DisposeHandle((Handle) srh);
- }
- return errCode;
- }
-
- /* GetDlogName - gets a string name for the dialog.
- 1.) we try to get title from name of ditl resource
- 2.) we try to get title from name of associated dialog.
- 3.) we try to get title from windowName of assocaiated dialog.
- 4.) we just use the resource number.
-
- Note: as an optimization we check first for the DLOG with the same id as the
- DITL. if that fails, we loop over them all.
- */
- static void GetDlogName(const Handle h, Integer inRes, StringPtr dlogS){
- Integer saveRes;
- Integer id, did;
- Integer i, max;
- OSType type, dtype;
- Str255 s;
- DialogTHndl dt;
-
- GetResInfo(h, &id, &type, dlogS);
- if(0 == Length(dlogS)){
- saveRes = CurResFile();
- UseResFile(inRes);
- if(NIL != (dt = (DialogTHndl) Get1Resource('DLOG', id)) &&
- id == (**dt).itemsID){
-
- GetResInfo((Handle) dt, &did, &dtype, dlogS);
- if(0 == Length(dlogS)){
- StrMove((**dt).title, dlogS);
- }
- }else{
- max = Count1Resources('DLOG');
- for(i = 1; i <= max ; i++){
- if(NIL != (dt = (DialogTHndl) Get1IndResource('DLOG', i)) &&
- id == (**dt).itemsID){
-
- GetResInfo((Handle) dt, &did, &dtype, dlogS);
- if(0 == Length(dlogS)){
- StrMove((**dt).title, dlogS);
- }
- break;
- }
- }
- }
- UseResFile(saveRes);
- }
- StripNonAlphaNum(dlogS);
- if(0 == Length(dlogS)){
- NumToString(id, s);
- if('-' == s[1]){
- s[1] = 'm';
- }
- StrMove(hS, dlogS);
- Concat(dlogS, s);
- }
- }
-
- /* CountTDItems - counts the number of items in the dialog template
- */
- static Integer CountTDItems(const Handle h){
- return 1 + **(Integer **) h;
- }
-
-
- /* SkipTDItem - skip an item in a DITL.
- */
- static Integer SkipTDItem(const Handle h, LongInt off){
- DitlItemPtr dip;
- Ptr p;
-
- dip = (DitlItemPtr) ((*h) + off);
- p = (Ptr) dip + sizeof(long) + sizeof(Rect) + 2 * sizeof(char) + dip->len;
- if(((LongInt) p) & 1){
- p++;
- }
- return p - *h;
- }
-
- /* GetCitlItem - get the title out of the CNTL resource template
- */
- static void GetCitlItem(Integer id, Integer inRes, StringPtr itemS){
- Integer saveResFile;
- Handle h;
- OSType type;
-
- saveResFile = CurResFile();
- UseResFile(inRes);
- if(NIL != (h = Get1Resource('CNTL', id))){
- LoadResource(h);
- StrMove( (** (CtlItemHandle) h).title, itemS);
- if(0 == Length(itemS)){
- GetResInfo(h, &id, &type, itemS);
- }
- HPurge(h);
- }
- UseResFile(saveResFile);
- if(0 == Length(itemS)){
- StrMove(cntlS, itemS);
- }
- }
-
- /* GetNonTextItem - get the title out of a non-text resource.
- */
- static void GetNonTextItem(StringPtr defaultS, OSType type, Integer id, Integer inRes, StringPtr itemS){
- Integer saveResFile;
- Handle h;
-
- saveResFile = CurResFile();
- UseResFile(inRes);
- SetResLoad(FALSE);
- if(NIL != (h = Get1Resource(type, id))){
- GetResInfo(h, &id, &type, itemS);
- }
- SetResLoad(TRUE);
- UseResFile(saveResFile);
- if(0 == Length(itemS)){
- StrMove(defaultS, itemS);
- }
- }
-
- /* GetTDItem - returns the 1s based item as a string in itemS
- */
- static void GetTDItem(const Handle h, Integer i, Integer inRes, StringPtr itemS){
- LongInt offset;
- DitlItemPtr dip;
- SignedByte state;
-
- for(offset = sizeof(Integer) ; i > 1 ; i--){
- offset = SkipTDItem(h, offset);
- }
- itemS[0] = '\0'; /* initialize */
- state = HGetState((Handle) h);
- HLock((Handle) h);
- dip = (DitlItemPtr) ((*h) + offset);
- switch(((unsigned char) dip->type) & ~itemDisable){
- case helpItem:
- HSetState((Handle) h, state);
- return; /* null string for this one */
- case ctrlItem|btnCtrl:
- StrMove((StringPtr) &dip->len, itemS);
- if(0 == Length(itemS)){
- StrMove(buttonS, itemS);
- }
- break;
- case ctrlItem|chkCtrl:
- StrMove((StringPtr) &dip->len, itemS);
- if(0 == Length(itemS)){
- StrMove(checkBoxS, itemS);
- }
- break;
- case ctrlItem|radCtrl:
- StrMove((StringPtr) &dip->len, itemS);
- if(0 == Length(itemS)){
- StrMove(radioButtonS, itemS);
- }
- break;
- case statText:
- StrMove((StringPtr) &dip->len, itemS);
- if(0 == Length(itemS)){
- StrMove(textS, itemS);
- }
- break;
- case editText:
- StrMove((StringPtr) &dip->len, itemS);
- if(0 == Length(itemS)){
- StrMove(editS, itemS);
- }
- break;
- case ctrlItem|resCtrl: GetCitlItem(dip->resID, inRes, itemS); break;
- case iconItem: GetNonTextItem(iconS, 'ICON', dip->resID, inRes, itemS); break;
- case picItem: GetNonTextItem(pictS, 'PICT', dip->resID, inRes, itemS); break;
- case userItem: StrMove(userS, itemS); break;
- default: StrMove(unknownS, itemS); break;
- }
- HSetState((Handle) h, state);
- }
-
- /* WriteHdlgDitlItem - write out an item to an hdlg resource.
- */
- static OSErr WriteHdlgDitlItem(const StringPtr itemS, const StringPtr dlogS, const StringPtr helpStrsS, const StringPtr nS, Integer outRef){
- Str255 s;
- OSErr errCode;
-
- if(NOT EqualString(oneS, nS, FALSE, FALSE)){ /* not first item, put a comma */
- if(noErr != (errCode = FSWriteStr(outRef, commaS))){
- return errCode;
- }
- }
- if(IsSkipItem(itemS)){
- GetIndString(s, kMainStrs, kSkipItemS);
- return FSWriteStr(outRef, s);
- }else{
- return WriteStrSharp(kHDLGStringResStrs, dlogS, helpStrsS, nS, outRef);
- }
- }
-
-
- /* BalloonifyDitl1 - put out the STR# and hdlg
- 1.) collect the replacement strings.
- 2.) dump out the initial header
- 3.) loop through the items
- 4.) dump out the midedial header
- 5.) loop through the items
- 6.) dump out the closer.
- */
- static OSErr BalloonifyDitl1(Handle h, Integer inRes, Integer outRef){
- OSErr errCode;
- Str255 dlogS;
- Str255 helpStrsS;
- Str255 itemS;
- Str255 idS;
- Str255 nS;
- Integer i, j, max, id;
- OSType type;
-
- errCode = noErr;
- dlogS[0] = helpStrsS[0] = itemS[0] = nS[0] = '\0';
-
- /* 1.) collect the replacement strings.
- */
- GetDlogName(h, inRes, dlogS);
- StrMove(dlogS, helpStrsS);
- errCode = BumpProgress(dlogS);
- Concat(dlogS, ditlS);
- Concat(helpStrsS, hdlgS);
-
- /* 2.) dump out the initial header
- */
- GetResInfo(h, &id, &type, idS);
- NumToString(id, idS);
- if(noErr == errCode){ errCode = WriteStrSharp(kHDLGNormal1Strs, dlogS, helpStrsS, idS, outRef); }
-
- /* 3.) loop through the items
- */
- max = CountTDItems(h);
- for(i = 1, j = 1 ; i <= max && noErr == errCode; i++){
- NumToString(j, nS);
- GetTDItem(h, i, inRes, itemS);
- if(NOT (IsSkipItem(itemS))){
- errCode = WriteStrItem(itemS, dlogS, helpStrsS, nS, outRef);
- j++;
- }
- }
-
- /* 4.) dump out the medial header
- */
- if(noErr == errCode){ errCode = WriteStrSharp(kHDLGMedialStrs, dlogS, helpStrsS, nS, outRef); }
-
- /* 5.) loop through the items
- */
- for(i = 1, j = 1; i <= max && noErr == errCode; i++){
- NumToString(j, nS);
- GetTDItem(h, i, inRes, itemS);
- errCode = WriteHdlgDitlItem(itemS, dlogS, helpStrsS, nS, outRef);
- if(NOT (IsSkipItem(itemS))){
- j++;
- }
- }
-
- /* 6.) dump out the closer.
- */
- if(noErr == errCode){ errCode = WriteStrSharp(kHDLGCloseStrs, dlogS, helpStrsS, nS, outRef); }
- return errCode;
- }
-
-
- /* BalloonifyDialogs - for each DITL, write the ditl's STR#, write the ditl's 'hdlg'
- this sorts the ditls.
- */
- static OSErr BalloonifyDialogs(Integer inRes, Integer outRef){
- OSErr errCode;
- Integer i, max;
- Integer saveResFile;
- Handle h;
- SortResHandle srh;
-
- errCode = noErr;
- saveResFile = CurResFile();
- UseResFile(inRes);
-
- /* get the sorted resources.
- */
- if(noErr != (errCode = NewSortedRes('DITL', &srh))){
- return errCode;
- }
- max = GetHandleSize((Handle) srh) / sizeof(SortResRec);
-
-
- /* process the sorted ditls.
- */
- for(i = 0; i < max && noErr == errCode ; i++){
- h = (*srh)[i].h;
- LoadResource(h);
- if(noErr != (errCode = ResError())){
- break;
- }
- HNoPurge(h);
- HLock(h);
- UseResFile(saveResFile);
- errCode = BalloonifyDitl1(h, inRes, outRef);
- UseResFile(inRes);
- ReleaseResource(h);
- }
- UseResFile(saveResFile);
- if(NIL != srh){
- DisposeHandle((Handle) srh);
- }
- return errCode;
- }
-
-
- /* Balloonify -
- Note: what if we attempt to open ourself?
- */
- OSErr Balloonify(FSSpecPtr fs, ScriptCode script){
- OSErr errCode;
- Integer res, outRefNum;
- Integer saveResFile;
- FSSpec outFileSpec;
- Str255 suffixS, creatorS, typeS;
- OSType creator, type;
-
- errCode = noErr;
- saveResFile = CurResFile();
- outRefNum = -1;
- GetIndString(suffixS, kMainStrs, kSuffixS);
- GetIndString(creatorS, kMainStrs, kCreatorS);
- GetIndString(typeS, kMainStrs, kTypeS);
- BlockMove(&creatorS[1], &creator, sizeof(OSType));
- BlockMove(&typeS[1], &type, sizeof(OSType));
-
- /* Open the input file.
- */
- if(-1 == (res = FSpOpenResFile(fs, fsRdPerm))){
- errCode = ResError();
- }
-
- /* Create the output file
- */
- if(noErr == errCode){
- UseResFile(saveResFile);
- outFileSpec = *fs;
- if(Length(outFileSpec.name) > 31 - Length(suffixS)){
- outFileSpec.name[0] = 31 - Length(suffixS);
- }
- Concat(outFileSpec.name, suffixS);
- errCode = FSpCreate(&outFileSpec, creator, type, script);
- }
-
- /* open the output file.
- */
- if(noErr == errCode){
- errCode = FSpOpenDF(&outFileSpec, fsWrPerm, &outRefNum);
- }
- if(noErr == errCode){
- errCode = BalloonifyHeader(outFileSpec.name, outRefNum);
- }
- if(noErr == errCode){
- StartProgress();
- errCode = BalloonifyMenus(res, outRefNum);
- }
- if(noErr == errCode){
- errCode = BalloonifyDialogs(res, outRefNum);
- }
- StopProgress(); /* safe to call even if StartProgress never called */
-
- /* close the output file.
- if an error occurred, delete the output file, if we created and opened it.
- */
- if(-1 != outRefNum){
- if(noErr == errCode){
- errCode = FSClose(outRefNum);
- }else{
- FSClose(outRefNum);
- }
- if(noErr == errCode){
- errCode = FlushVol(NIL, outFileSpec.vRefNum);
- }else{
- FlushVol(NIL, outFileSpec.vRefNum);
- }
- if(noErr != errCode){ /* if an error occurred, delete the output file */
- FSpDelete(&outFileSpec);
- }
- }
-
- /* close the input file.
- */
- if(-1 != res){
- CloseResFile(res);
- if(noErr == errCode){
- errCode = ResError();
- }
- }
- return errCode;
- }
-